﻿// (c) Copyright Michael Antonio.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved
using System.Collections.Generic;
using System;
using System.Reflection;
using System.Linq;
using Subsonic.Data;
using MichMan.Utilities.Requests;
using MichMan.Utilities;

namespace Subsonic
{
    public abstract class Choice
    {
        public Choice()
        {
            Values = new List<string>();
        }

        public static Choice GetChoice(string choiceType)
        {
            Type type = Type.GetType(choiceType);
            if (type != null && typeof(Choice).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
            {
                return (Choice)Activator.CreateInstance(type);
            }
            return null;
        }

        public string Title { get; protected set; }
        public List<string> Values { get; private set; }
        public string CurrentValue { get { return Values[SelectedItem]; } }
        public int SelectedItem { get; protected set; }
        public abstract bool SetNewValue(string value);
    }

    public abstract class ChoiceList<T> : Choice where T : IComparable
    {
        public ChoiceList(Action<T> setter, Func<T> getter)
        {
            Setter = setter;
            Getter = getter;
            Init();
            Values.AddRange(from kvp in ValueMap select kvp.Key);
            T currentValue = getter();

            if (ValueMap.Any(kvp => kvp.Value.CompareTo(currentValue) == 0))
            {
                SelectedItem = ValueMap.IndexOf(ValueMap.First(kvp => kvp.Value.CompareTo(currentValue) == 0));
            }
        }

        protected abstract void Init();

        Action<T> Setter { get; set; }
        Func<T> Getter { get; set; }

        public List<KeyValuePair<string, T>> ValueMap = new List<KeyValuePair<string, T>>();

        public override bool SetNewValue(string newValue)
        {
            if (!ValueMap.Any(kvp => kvp.Key == newValue))
            {
                return false;
            }

            T value = ValueMap.First(kvp => kvp.Key == newValue).Value;

            Setter( value );
            SubsonicSettings.Save();

            return true;
        }
    }

    public class PlayModeChoice : ChoiceList<PlayMode>
    {
        public PlayModeChoice() : base(v => SubsonicSettings.Instance.PlayMode = v, () => SubsonicSettings.Instance.PlayMode) { }

        protected override void Init()
        {
            Title = "{settings_playmode}";
            ValueMap.Add(new KeyValuePair<string, PlayMode>("{settings_playmode_stream}", PlayMode.Stream));
            ValueMap.Add(new KeyValuePair<string, PlayMode>("{settings_playmode_download}", PlayMode.Download));
            ValueMap.Add(new KeyValuePair<string, PlayMode>("{settings_playmode_offline}", PlayMode.Offline));
            ValueMap.Add(new KeyValuePair<string, PlayMode>("{settings_playmode_jukebox}", PlayMode.Jukebox));
        }
    }

    public class SongsToPreLoadChoice : ChoiceList<int>
    {
        public SongsToPreLoadChoice() : base(v => SubsonicSettings.Instance.SongsToPreLoad = v, () => SubsonicSettings.Instance.SongsToPreLoad) { }

        protected override void Init()
        {
            Title = "{settings_preload}";
            ValueMap.Add(new KeyValuePair<string, int>("{settings_preload_1}", 1));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_preload_2}", 2));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_preload_3}", 3));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_preload_5}", 5));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_preload_10}", 10));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_preload_unlimited}", int.MaxValue));
        }
    }

    public class CacheSizeChoice : ChoiceList<int>
    {
        public CacheSizeChoice()
            : base(v => SubsonicSettings.Instance.CacheSize = v, () => SubsonicSettings.Instance.CacheSize)
        {
        }

        protected override void Init()
        {
            Title = "{settings_cache_size}";
            ValueMap.Add(new KeyValuePair<string, int>("{settings_cache_size_500}", 500));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_cache_size_1000}", 1000));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_cache_size_2000}", 2000));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_cache_size_5000}", 5000));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_cache_size_10000}", 10000));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_cache_size_20000}", 20000));
            ValueMap.Add(new KeyValuePair<string, int>("{settings_cache_size_unlimited}", int.MaxValue));
        }
    }

    public class MobileBitRateChoice : BitRateChoice
    {
        public MobileBitRateChoice()
            : base(v => SubsonicSettings.Instance.MobileBitRate = v, () => SubsonicSettings.Instance.MobileBitRate)
        {
            Title = "{settings_max_bitrate_mobile}";
        }
    }

    public class WiFiBitRateChoice : BitRateChoice
    {
        public WiFiBitRateChoice()
            : base(v => SubsonicSettings.Instance.WiFiBitRate = v, () => SubsonicSettings.Instance.WiFiBitRate)
        {
            Title = "{settings_max_bitrate_wifi}";
        }
    }

    public abstract class BitRateChoice : ChoiceList<BitRate>
    {
        public BitRateChoice(Action<BitRate> setter, Func<BitRate> getter) : base(setter, getter) { }

        protected override void Init()
        {
            ValueMap.Add(new KeyValuePair<string, BitRate>("{settings_max_bitrate_96}", BitRate.BitRate96Kbps));
            ValueMap.Add(new KeyValuePair<string, BitRate>("{settings_max_bitrate_128}", BitRate.BitRate128Kbps));
            ValueMap.Add(new KeyValuePair<string, BitRate>("{settings_max_bitrate_160}", BitRate.BitRate160Kbps));
            ValueMap.Add(new KeyValuePair<string, BitRate>("{settings_max_bitrate_320}", BitRate.BitRate320Kbps));
            ValueMap.Add(new KeyValuePair<string, BitRate>("{settings_max_bitrate_unlimited}", BitRate.BitRateUnlimited));
        }

    }

    public class ServerChoice : ChoiceList<int>
    {
        public ServerChoice() : base(v => SubsonicSettings.Instance.CurrentServer = v, () => SubsonicSettings.Instance.CurrentServer) { }

        protected override void Init()
        {
            Title = "{settings_servers_title}";
            int i = 0;
            foreach (var svr in SubsonicSettings.Instance.Servers)
            {
                ValueMap.Add(new KeyValuePair<string, int>(svr.Name, i++));
            }
        }

        public override bool SetNewValue(string newValue)
        {
            if (newValue != this.CurrentValue)
            {
//                ApplicationRunId.Instance.Value = Guid.NewGuid();
                new LocalCache().Clear();
            }

            return base.SetNewValue(newValue);
        }
    }

}